package cn.wjssl.trigger.http;

import cn.wjssl.domain.activity.service.IRaffleActivityAccountQuotaService;
import cn.wjssl.domain.strategy.model.entity.RaffleAwardEntity;
import cn.wjssl.domain.strategy.model.entity.RaffleFactorEntity;
import cn.wjssl.domain.strategy.model.entity.StrategyAwardEntity;
import cn.wjssl.domain.strategy.model.valobj.RuleWeightVO;
import cn.wjssl.domain.strategy.service.IRaffleAward;
import cn.wjssl.domain.strategy.service.IRaffleRule;
import cn.wjssl.domain.strategy.service.IStrategyService;
import cn.wjssl.domain.strategy.service.armory.IStrategyArmory;
import cn.wjssl.trigger.api.IRaffleStrategyService;
import cn.wjssl.trigger.api.dto.*;
import cn.wjssl.types.enums.ResponseCode;
import cn.wjssl.types.exception.AppException;
import cn.wjssl.types.model.Response;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 抽奖接口
 */
@Slf4j
@RestController()
@CrossOrigin("${app.config.cross-origin}")
@RequestMapping("/api/${app.config.api-version}/raffle/strategy")
@DubboService(version = "1.0")
public class RaffleStrategyController implements IRaffleStrategyService {

    @Resource
    private IRaffleAward raffleAward;
    @Resource
    private IRaffleRule raffleRule;
    @Resource
    private IStrategyService raffleStrategy;
    @Resource
    private IStrategyArmory strategyArmory;
    @Resource
    private IRaffleActivityAccountQuotaService accountQuotaService;

    // 测试
    @RequestMapping(value = "test" , method = RequestMethod.GET)
    public Response<String> test() {
        return Response.<String>builder()
                .code(ResponseCode.SUCCESS.getCode())
                .info(ResponseCode.SUCCESS.getInfo())
                .data("测试成功 !!!").build();
    }


    /**
     * 策略装配，将策略信息装配到缓存中
     * <a href="http://localhost:8091/api/v1/raffle/strategy_armory">/api/v1/raffle/strategy/strategy_armory</a>
     *
     * @param strategyId 策略ID
     * @return 装配结果
     */
    @RequestMapping(value = "strategy_armory", method = RequestMethod.GET)
    @Override
    public Response<Boolean> strategyArmory(Long strategyId) {
        try {
            log.info("抽奖策略装配开始 strategyId：{}", strategyId);
            boolean armoryStatus = strategyArmory.assembleLotteryStrategy(strategyId);
            Response<Boolean> response = Response.<Boolean>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(armoryStatus)
                    .build();
            log.info("抽奖策略装配完成 strategyId：{} response: {}", strategyId, JSON.toJSONString(response));
            return response;
        } catch (Exception e) {
            log.error("抽奖策略装配失败 strategyId：{}", strategyId, e);
            return Response.<Boolean>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    /**
     * 查询奖品列表
     * <a href="http://localhost:8091/api/v1/raffle/query_raffle_award_list">/api/v1/raffle/strategy/query_raffle_award_list</a>
     * 请求参数 raw json
     *
     * @param request {"activityId":100301,"userId":"lxd"}
     * @return 奖品列表
     */
    @RequestMapping(value = "query_raffle_award_list", method = RequestMethod.POST)
    @Override
    public Response<List<RaffleAwardListResponseDTO>> queryRaffleAwardList(@RequestBody RaffleAwardListRequestDTO request) {
       try {
           log.info("查询抽奖奖品列表配开始 userId:{} activityId：{}", request.getUserId(), request.getActivityId());
           // 1. 参数校验
           if (StringUtils.isBlank(request.getUserId()) || null == request.getActivityId()) {
               throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
           }
           // 2. 根据activityId 来获取对应的strategyId, 再从 strategy_award 表获取策略奖品列表
           List<StrategyAwardEntity> strategyAwardEntities = raffleAward.queryStrategyAwardListByActivityId(request.getActivityId());

           // 3. 从奖品实体中获取对应的规则ruleModels转变成数组 -->  tree_lock_1等等, 这里的ruleModels相当于treeId
           // ["tree_luck_award", "tree_luck_award", "tree_luck_award", "tree_luck_award", "tree_lock_3", "tree_lock_2", "tree_lock_1", "tree_luck_award"]
           String[] treeIds = strategyAwardEntities.stream()
                   .map(StrategyAwardEntity::getRuleModels)
                   .filter(ruleModel -> ruleModel != null && !ruleModel.isEmpty())
                   .toArray(String[]::new);
           /**
            * 4. 根据treeId, 获取 树规则rule_key 为 rule_lock 的节点, 并获取该节点对应的规则rule_value --> 抽奖多少次解锁
            * map格式: {rule_key, rule_value}
            * awardLockCountMap: [{tree_lock_3, 3}, {tree_lock_2, 2}, {tree_lock_1, 1}]
            */
           Map<String, Integer> awardLockCountMap = raffleRule.queryAwardRuleLockCount(treeIds);

           // 5. 获取用户 [当日] 抽奖次数
           Integer userDayRaffleCount = accountQuotaService.queryRaffleActivityAccountDayPartakeCount(request.getActivityId(), request.getUserId());

           // 6. 将列表映射成 RaffleAwardListResponseDTO 类
           List<RaffleAwardListResponseDTO> responseDTOS = new ArrayList<>(strategyAwardEntities.size());
           for (StrategyAwardEntity strategyAwardEntity : strategyAwardEntities) {
               // 从奖品解锁次数map中 获取对应的解锁次数
               Integer awardLockCount = awardLockCountMap.get(strategyAwardEntity.getRuleModels());
               responseDTOS.add(RaffleAwardListResponseDTO.builder()
                       .awardId(strategyAwardEntity.getAwardId())
                       .awardTitle(strategyAwardEntity.getAwardTitle())
                       .awardSubtitle(strategyAwardEntity.getAwardSubtitle())
                       .sort(strategyAwardEntity.getSort())
                       .awardRuleLockCount(awardLockCount)  // 奖品解锁次数
                       .isAwardUnlock(null == awardLockCount || awardLockCount <= userDayRaffleCount)  // 比较抽奖次数, 是否解锁
                       //  差多少抽解锁, 解锁次数小于用户抽奖次数, 那就说明已经解锁了, 相当于还需要0抽; 如果用户抽奖次数更少, 那就相减
                       .waitUnLockCount(null == awardLockCount || awardLockCount <= userDayRaffleCount ? 0 : awardLockCount - userDayRaffleCount)
                       .build());
           }
           // 7. 装配结果
           Response<List<RaffleAwardListResponseDTO>> response = Response.<List<RaffleAwardListResponseDTO>>builder()
                   .code(ResponseCode.SUCCESS.getCode())
                   .info(ResponseCode.SUCCESS.getInfo())
                   .data(responseDTOS)
                   .build();
           log.info("查询抽奖奖品列表配置完成 userId:{} activityId：{} response: {}", request.getUserId(), request.getActivityId(), JSON.toJSONString(response));
           // 8. 返回结果
           return response;
       }catch (Exception e) {
           log.error("查询抽奖奖品列表配置失败 userId:{} activityId：{}", request.getUserId(), request.getActivityId(), e);
           return Response.<List<RaffleAwardListResponseDTO>>builder()
                   .code(ResponseCode.UN_ERROR.getCode())
                   .info(ResponseCode.UN_ERROR.getInfo())
                   .build();
       }
    }

    /**
     * 随机抽奖接口
     * <a href="http://localhost:8091/api/v1/raffle/random_raffle">/api/v1/raffle/strategy/random_raffle</a>
     *
     * @param requestDTO 请求参数 {"strategyId":100006}
     * @return 抽奖结果
     */
    @RequestMapping(value = "random_raffle", method = RequestMethod.POST)
    @Override
    public Response<RaffleStrategyResponseDTO> randomRaffle(@RequestBody RaffleStrategyRequestDTO requestDTO) {
        try {
            log.info("随机抽奖开始 strategyId: {}", requestDTO.getStrategyId());
            // 先默认userId
            RaffleAwardEntity raffleAwardEntity = raffleStrategy.performRaffle(RaffleFactorEntity.builder()
                    .strategyId(requestDTO.getStrategyId())
                    .userId("lxd")
                    .build());
            // 装配响应类
            Response<RaffleStrategyResponseDTO> response = Response.<RaffleStrategyResponseDTO>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(RaffleStrategyResponseDTO.builder()
                            .awardId(raffleAwardEntity.getAwardId())
                            .awardIndex(raffleAwardEntity.getSort())
                            .build())
                    .build();
            log.info("随机抽奖完成 strategyId: {} response: {}", requestDTO.getStrategyId(), JSON.toJSONString(response));
            return response;
        } catch (AppException e) {
            log.error("随机抽奖失败 strategyId：{} {}", requestDTO.getStrategyId(), e.getInfo());
            return Response.<RaffleStrategyResponseDTO>builder()
                    .code(e.getCode())
                    .info(e.getInfo())
                    .build();
        } catch (Exception e) {
            log.error("随机抽奖失败 strategyId：{}", requestDTO.getStrategyId(), e);
            return Response.<RaffleStrategyResponseDTO>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }

    /**
     * 查询策略抽奖权重规则
     * curl --request POST \
     * --url http://localhost:8091/api/v1/raffle/strategy/query_raffle_strategy_rule_weight \
     * --header 'content-type: application/json' \
     * --data '{
     * "userId":"lxd",
     * "activityId": 100301
     * }'
     */
    @RequestMapping(value = "query_raffle_strategy_rule_weight", method = RequestMethod.POST)
    @Override
    public Response<List<RaffleStrategyRuleWeightResponseDTO>> queryRaffleStrategyRuleWeight(@RequestBody RaffleStrategyRuleWeightRequestDTO request) {
        try {
            log.info("查询抽奖策略权重规则配置开始 userId:{} activityId：{}", request.getUserId(), request.getActivityId());
            // 1. 参数校验
            if (StringUtils.isBlank(request.getUserId()) || null == request.getActivityId()) {
                throw new AppException(ResponseCode.ILLEGAL_PARAMETER.getCode(), ResponseCode.ILLEGAL_PARAMETER.getInfo());
            }
            // 2. 查询用户 [当前] 抽奖次数
            Integer userTotalPartakeCount = accountQuotaService.queryRaffleActivityAccountTotalPartakeCount(request.getActivityId(), request.getUserId());

            /**
             * 3. 查询权重配置
             * 通过activityId, 查询strategyId, 用策略Id, 查询strategy_rule表, 获得权重配置(rule_value)
             * 再通过权重配置, 查询strategy_award表, 查询奖品相关, 组装成权重奖品配置列表ruleWeightVOS
             * 优先从redis中获取
             *
             */
            List<RuleWeightVO> ruleWeightVOSList = raffleRule.queryAwardRuleWeightByActivityId(request.getActivityId());

            // 4. 转换成接口响应对象列表
            List<RaffleStrategyRuleWeightResponseDTO> responseDTOList = new ArrayList<>();
            /**
             * ruleWeightVO 相当于:
             * RuleWeightVO.builder()
             *     .ruleValue(ruleValue)  // 60:102 4000:102,103,104,105 5000:102,103,104,105,106,107 6000:102,103,104,105,106,107,108
             *     .weight(Integer.valueOf(ruleValueKey.split(Constants.COLON)[0]))    // 4000
             *     .awardIds(awardIds)     // [102,103,104,105]
             *     .awardList(awardList)   // [102的AwardVO(awardId, awardTitle), 103的AwardVO(awardId, awardTitle), ....]
             *     .build());
             */
            for (RuleWeightVO ruleWeightVO : ruleWeightVOSList) {
                List<RaffleStrategyRuleWeightResponseDTO.StrategyAward> responseDTOAwardList = new ArrayList<>();
                List<RuleWeightVO.Award> awardVOList = ruleWeightVO.getAwardList();   // [102的AwardVO(awardId, awardTitle), 103的AwardVO(awardId, awardTitle), ....]
                for (RuleWeightVO.Award awardVO : awardVOList) {    // 102的AwardVO(awardId, awardTitle)
                    // 把 awardVO 映射成 StrategyAward, 实际上是一样的东西, 就是awardId 和 awardTitle
                    responseDTOAwardList.add(RaffleStrategyRuleWeightResponseDTO.StrategyAward.builder()
                            .awardId(awardVO.getAwardId())
                            .awardTitle(awardVO.getAwardTitle())
                            .build()
                    );
                }
                // 封装 responseDTO 对象
                RaffleStrategyRuleWeightResponseDTO responseDTO = RaffleStrategyRuleWeightResponseDTO.builder()
                        .ruleWeightCount(ruleWeightVO.getWeight())
                        .strategyAwards(responseDTOAwardList)
                        .userActivityAccountTotalUseCount(userTotalPartakeCount)
                        .build();
                // 加入列表
                responseDTOList.add(responseDTO);
            }
            // 5. 返回响应结果
            Response<List<RaffleStrategyRuleWeightResponseDTO>> response = Response.<List<RaffleStrategyRuleWeightResponseDTO>>builder()
                    .code(ResponseCode.SUCCESS.getCode())
                    .info(ResponseCode.SUCCESS.getInfo())
                    .data(responseDTOList)
                    .build();
            log.info("查询抽奖策略权重规则配置完成 userId:{} activityId：{} response: {}", request.getUserId(), request.getActivityId(), JSON.toJSONString(response));
            return response;
        }catch (Exception e) {
            log.error("查询抽奖策略权重规则配置失败 userId:{} activityId：{}", request.getUserId(), request.getActivityId(), e);
            return Response.<List<RaffleStrategyRuleWeightResponseDTO>>builder()
                    .code(ResponseCode.UN_ERROR.getCode())
                    .info(ResponseCode.UN_ERROR.getInfo())
                    .build();
        }
    }
}
